package org.bronycorps.mlptss.domain.actor;

import org.bronycorps.mlptss.domain.controller.AbstractController;
import org.bronycorps.mlptss.domain.controller.EnemyController;
import org.bronycorps.mlptss.domain.model.AbstractActorModel;
import org.bronycorps.mlptss.domain.model.Enemy.State;
import org.bronycorps.mlptss.domain.model.event.StateChangeEvent;
import org.bronycorps.mlptss.domain.model.event.StateChangeEventListener;
import org.bronycorps.mlptss.manager.CollisionManager;
import org.bronycorps.mlptss.manager.TrajectFactory;
import org.bronycorps.mlptss.manager.preferences.AssetsConfiguration;
import org.bronycorps.mlptss.manager.preferences.GameConfiguration;
import org.bronycorps.mlptss.utils.AnimationCache;
import org.bronycorps.mlptss.utils.DrawableAnimation;

import com.badlogic.gdx.math.Vector2;

public class EnemyActor extends AbstractActor implements
		StateChangeEventListener {

	private DrawableAnimation bubbleHitAnimation;
	private DrawableAnimation chainExplodeAnimation;
	private EnemyController enemyController;
	private DrawableAnimation explodeAnimation;
	private DrawableAnimation hitAnimation;

	public EnemyActor(EnemyController enemyController) {
		super();
		this.enemyController = enemyController;
		enemyController.getModel().addListener(this);

		createAnimation();

		setDrawable(this.currentAnimation.getDrawableKeyFrame(this.currentTime));
		setPosition(getModelPosition().x, getModelPosition().y);
		setWidth(getPrefWidth());
		setHeight(getPrefHeight());
		setOrigin(getModelOrigin().x, getModelOrigin().y);

		this.hitBox.setWidth(getBounds().width);
		this.hitBox.setHeight(getBounds().height);
	}

	@Override
	public void act(float delta) {
		super.act(delta);

		switch (this.enemyController.getModel().getState()) {
		case EXPLODE:
			if (this.currentAnimation.isAnimationFinished(this.currentTime)) {
				this.enemyController.getModel().setState(State.CHAIN_EXPLODE);
			}
			break;
		case EXPLODE_NO_CHAIN:
		case CHAIN_EXPLODE:
			if (this.currentAnimation.isAnimationFinished(this.currentTime)) {
				terminate();
			}
			break;
		case HIT:
			if (this.currentAnimation.isAnimationFinished(this.currentTime)) {
				this.enemyController.getModel().setState(State.NORMAL);
			}
			break;
		default:
			break;
		}
	}

	private void createAnimation() {
		AssetsConfiguration config = GameConfiguration.getInstance()
				.getCurrentMod().getAssetsConfiguration();

		// explode animation
		this.explodeAnimation = this.enemyController.getModel()
				.getExplosionAnimation();

		this.chainExplodeAnimation = AnimationCache.getInstance().get(
				config.getCommonExplosionAnimationName());

		// hit animation
		this.hitAnimation = this.enemyController.getModel().getHitAnimation();
		this.bubbleHitAnimation = this.enemyController.getModel()
				.getBubbleHitAnimation();

		this.currentAnimation = getDefaultAnimation();
	}

	@Override
	protected AbstractController getController() {
		return this.enemyController;
	}

	private DrawableAnimation getDefaultAnimation() {
		if (this.enemyController.getModel().isBubble()) {
			return this.enemyController.getModel().getBubbleAnimation();
		} else {
			return this.enemyController.getModel().getDefaultAnimation();
		}
	}

	public EnemyController getEnemyController() {
		return this.enemyController;
	}

	private DrawableAnimation getHitAnimation() {
		if (this.enemyController.getModel().isBubble()) {
			return this.bubbleHitAnimation;
		} else {
			return this.hitAnimation;
		}
	}

	@Override
	public AbstractActorModel getModel() {
		return this.enemyController.getModel();
	}

	@Override
	protected Vector2 getModelPosition() {
		return this.enemyController.getModel().getPosition();
	}

	@Override
	public void onStateChange(StateChangeEvent event) {
		switch (event.getEnemy().getState()) {
		case CHAIN_EXPLODE:
			switchAnimation(this.chainExplodeAnimation);
			CollisionManager.getInstance().chainExplode(this);
			break;
		case EXPLODE_NO_CHAIN:
		case EXPLODE:
			// when exploding, the entity must not move anymore
			TrajectFactory.getInstance().clearTweens(this);
			// switch to explosion animation
			switchAnimation(this.explodeAnimation);
			break;
		case HIT:
			switchAnimation(getHitAnimation());
			break;
		default:
			switchAnimation(getDefaultAnimation());
			break;
		}
	}

	public void terminate() {
		getTrack().removeEnemy(this);
	}

}
